package com.alvin.mbp.dao;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

import org.apache.log4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.BeanPropertyRowMapper;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.RowMapperResultSetExtractor;

import com.alvin.mbp.entity.BaseEntity;
import com.alvin.mbp.util.JDBCName;
import com.alvin.mbp.util.ReflectionUtils;

public class BaseDao<T extends BaseEntity> {

	private static Logger LOGGER = Logger.getLogger(BaseDao.class);

	private JdbcTemplate jdbcTemplate;

	protected Class<T> entityClass;

	/**
	 * 构造方法
	 */
	public BaseDao() {
		this.entityClass = ReflectionUtils.getSuperClassGenricType(getClass());
	}

	@Autowired
	public void setJdbcTemplate(JdbcTemplate jdbcTemplate) {
		this.jdbcTemplate = jdbcTemplate;
	}

	public JdbcTemplate getJdbcTemplate() {
		return jdbcTemplate;
	}

	/**
	 * 查询所有的结果
	 * 
	 * @return
	 */
	public List<T> findAll() {
		LOGGER.info(entityClass.getName());
		List<T> list = null;
		try {
			String sql = "select * from " + getTableName();
			LOGGER.info(sql);
			list = jdbcTemplate.query(sql, getRowMapper());
		} catch (Exception e) {
			LOGGER.error(e);
		}
		return list;
	}

	public List<T> findAll(int topNum) {
		LOGGER.info(entityClass.getName());
		List<T> list = null;
		try {
			String sql = "select * from " + getTableName() + " order by insert_time desc limit 0," + topNum;
			LOGGER.info(sql);
			list = jdbcTemplate.query(sql, getRowMapper());
		} catch (Exception e) {
			LOGGER.error(e);
		}
		return list;
	}

	public List<T> findBySql(String sql, Object[] params) {
		LOGGER.info(entityClass.getName());
		List<T> list = null;
		try {
			list = jdbcTemplate.query(sql, params, getRowMapper());
		} catch (Exception e) {
			LOGGER.error(e);
		}
		return list;
	}

	public List<T> findByProperty(String property, Object value) {
		LOGGER.info(entityClass.getName());
		List<T> list = null;
		try {
			String sql = "select * from " + getTableName() + " where " + property + " = ?";
			Object[] prams = { value };

			list = jdbcTemplate.query(sql, prams, getRowMapper());
		} catch (Exception e) {
			LOGGER.error(e);
		}
		return list;
	}

	public List<T> findByProperty(String property, Object value, int topNum) {
		LOGGER.info(entityClass.getName());
		List<T> list = null;
		try {
			String sql = "select * from " + getTableName() + " where " + property + " = ? order by insert_time desc limit 0," + topNum;
			Object[] prams = { value };

			list = jdbcTemplate.query(sql, prams, getRowMapper());
		} catch (Exception e) {
			LOGGER.error(e);
		}
		return list;
	}

	public T findByPropertyOne(String property, Object value) {
		List<T> list = findByProperty(property, value);
		return list == null || list.isEmpty() ? null : list.get(0);
	}

	public void updateByID(Integer id, String property, Object value) {
		try {
			String sql = "update " + this.getTableName() + " set " + property + " = ? where id = ?";
			int r = jdbcTemplate.update(sql, value, id);
			LOGGER.info("update :" + r);
		} catch (Exception e) {
			LOGGER.error(e);
		}
	}

	public T findById(Integer id) {
		List<T> list = findByProperty("id", id);
		return list == null || list.isEmpty() ? null : list.get(0);
	}

	private String getTableName() {
		return entityClass.getAnnotation(JDBCName.class).value();
	}

	private RowMapperResultSetExtractor<T> getRowMapper() {
		return new RowMapperResultSetExtractor<T>(new BeanPropertyRowMapper<T>(entityClass));
	}

	public void save(T entity) {
		try {
			Map<String, Object> map = entity.getEntityMap();
			String cols = "";
			String vals = "";
			Iterator<String> keys = map.keySet().iterator();
			List<Object> params = new ArrayList<Object>();
			while (keys.hasNext()) {
				String key = keys.next();
				if (map.get(key) != null) {
					cols += key + ",";
					params.add(map.get(key));
					vals += "?,";
				}

			}
			vals = vals.substring(0, vals.lastIndexOf(","));
			cols = cols.substring(0, cols.lastIndexOf(","));
			String sql = "insert into " + getTableName() + " (" + cols + ") values (" + vals + ")";
			LOGGER.info(sql);
			this.jdbcTemplate.update(sql, params.toArray());
		} catch (Exception e) {
			LOGGER.error(e);
		}
	}

	public void update(T entity) {
		try {
			Map<String, Object> map = entity.getEntityMap();
			String sets = "";
			Iterator<String> keys = map.keySet().iterator();
			List<Object> params = new ArrayList<Object>();
			while (keys.hasNext()) {
				String key = keys.next();
				if (map.get(key) != null) {
					sets += key + "= ?,";
					params.add(map.get(key));
				}

			}
			sets = sets.substring(0, sets.lastIndexOf(","));
			String sql = "update " + getTableName() + " set " + sets + " where id = ?";
			params.add(entity.getId());
			LOGGER.info("update:" + sql);
			this.jdbcTemplate.update(sql, params.toArray());
		} catch (Exception e) {
			LOGGER.error(e);
		}
	}
}
